import {ElMessage, ElMessageBox} from "element-plus";
import {sys} from "./params";
import {loginAfter} from "../network/login/test";

//判断变量是否为null或空字符串（包括空格字符）
export function checkStrIsEmpty(str){
    return str === null || str === '';
}

// import {ElMessage} from "element-plus";
// ElMessage.success('')

// import 'js-md5'
export function setCookie(key,value) {
    var d = new Date();
    d.setTime(d.getTime()+(24*60*60*1000));//cookie有效期(1天)
    var expires = "expires="+d.toGMTString();
    document.cookie = key + "=" + value + "; " + expires;
}

export function getCookie(key) {
    var name = key + "=";
    var ca = document.cookie.split(';');
    for(var i=0; i<ca.length; i++)
    {
        var c = ca[i].trim();
        if (c.indexOf(name)===0) return c.substring(name.length,c.length);
    }
    return "";
}


/*浮点数加减乘除运算*/
export var floatObj = function() {

    /*
     * 判断obj是否为一个整数
     */
    function isInteger(obj) {
        return Math.floor(obj) === obj
    }

    /*
     * 将一个浮点数转成整数，返回整数和倍数。如 3.14 >> 314，倍数是 100
     * @param floatNum {number} 小数
     * @return {object}
     *   {times:100, num: 314}
     */
    function toInteger(floatNum) {
        var ret = {times: 1, num: 0}
        var isNegative = floatNum < 0
        if (isInteger(floatNum)) {
            ret.num = floatNum
            return ret
        }
        var strfi  = floatNum + ''
        var dotPos = strfi.indexOf('.')
        var len    = strfi.substr(dotPos+1).length
        var times  = Math.pow(10, len)
        var intNum = parseInt(Math.abs(floatNum) * times + 0.5, 10)
        ret.times  = times
        if (isNegative) {
            intNum = -intNum
        }
        ret.num = intNum
        return ret
    }

    /*
     * 核心方法，实现加减乘除运算，确保不丢失精度
     * 思路：把小数放大为整数（乘），进行算术运算，再缩小为小数（除）
     *
     * @param a {number} 运算数1
     * @param b {number} 运算数2
     * @param digits {number} 精度，保留的小数点数，比如 2, 即保留为两位小数
     * @param op {string} 运算类型，有加减乘除（add/subtract/multiply/divide）
     */
    function operation(a, b, digits, op) {
        var o1 = toInteger(a)
        var o2 = toInteger(b)
        var n1 = o1.num
        var n2 = o2.num
        var t1 = o1.times
        var t2 = o2.times
        var max = t1 > t2 ? t1 : t2
        var result = null
        switch (op) {
            case 'add':
                if (t1 === t2) { // 两个小数位数相同
                    result = n1 + n2
                } else if (t1 > t2) { // o1 小数位 大于 o2
                    result = n1 + n2 * (t1 / t2)
                } else { // o1 小数位 小于 o2
                    result = n1 * (t2 / t1) + n2
                }
                return result / max
            case 'subtract':
                if (t1 === t2) {
                    result = n1 - n2
                } else if (t1 > t2) {
                    result = n1 - n2 * (t1 / t2)
                } else {
                    result = n1 * (t2 / t1) - n2
                }
                return result / max
            case 'multiply':
                result = (n1 * n2) / (t1 * t2)
                return result
            case 'divide':
                result = (n1 / n2) * (t2 / t1)
                return result
        }
    }

    // 加减乘除的四个接口
    function add(a, b, digits) {
        return operation(a, b, digits, 'add')
    }
    function subtract(a, b, digits) {
        return operation(a, b, digits, 'subtract')
    }
    function multiply(a, b, digits) {
        return operation(a, b, digits, 'multiply')
    }
    function divide(a, b, digits) {
        return operation(a, b, digits, 'divide')
    }


    // exports
    return {
        add: add,
        subtract: subtract,
        multiply: multiply,
        divide: divide
    }
}();


/*时间格式化*/
Date.prototype.format = function (format) {
    var args = {
        "M+": this.getMonth() + 1,
        "d+": this.getDate(),
        "h+": this.getHours(),
        "m+": this.getMinutes(),
        "s+": this.getSeconds(),
        "q+": Math.floor((this.getMonth() + 3) / 3),  //quarter
        "S": this.getMilliseconds()
    };
    if (/(y+)/.test(format))
        format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (var i in args) {
        var n = args[i];
        if (new RegExp("(" + i + ")").test(format))
            format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? n : ("00" + n).substr(("" + n).length));
    }
    return format;
};
//计算开始时间到结束时间一共有多少天
Date.prototype.howManyDays = function (endTime){
    let end = new Date(endTime);
    let se = this - end;
    let days = se/24/60/60/1000 + 1;
    return days;
}
// alert(new Date().format("yyyy-MM-dd hh:mm:ss"));

const arrUtils = function (){
    
    //1.数组元素上移（没用）
    function elementMoveUp({arr,elIndex}){
        if(checkArr(arr)){
            if(elIndex===0){
                ElMessage.info('元素已在数组最前')
                return;
            }
            let el = arr[elIndex];
            arr.splice(elIndex,1);
            arr.splice(elIndex-1,0,el);
        }
    }
    
    //2.数组元素下移（没用）
    function elementMoveDown({arr,elIndex}){
        console.log('arr',arr)
        if(checkArr(arr)){
            let a = arr.get(0);
            let el = Object.assign({},arr[elIndex]);
            arr.splice(elIndex,1);
            arr.splice(elIndex+1,0,el);
            console.log('el',el);
            console.log('last',arr)
        }
    }
    
    //3.判断数组类型是否正确、长度是否为零
    function checkArr(arr){
        if(!Array.isArray(arr)){
            // console.log()
            ElMessage.info(`${arr}'不是一个数组'`);
            return false;
        }else if(arr.length===0){
            ElMessage.info(`数组长度为0`);
            return false;
        }
        return true;
    }
    return{
        elementMoveUp,
        elementMoveDown,
        checkArr
    }
}();
//工具
export const utils = function () {
    
    //深度比较两个js对象
    function deepCompare(x, y) {
        var i, l, leftChain, rightChain;

        function compare2Objects(x, y) {
            var p;

            // remember that NaN === NaN returns false
            // and isNaN(undefined) returns true
            if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') {
                return true;
            }

            // Compare primitives and functions.
            // Check if both arguments link to the same object.
            // Especially useful on the step where we compare prototypes
            if (x === y) {
                return true;
            }

            // Works in case when functions are created in constructor.
            // Comparing dates is a common scenario. Another built-ins?
            // We can even handle functions passed across iframes
            if ((typeof x === 'function' && typeof y === 'function') ||
                (x instanceof Date && y instanceof Date) ||
                (x instanceof RegExp && y instanceof RegExp) ||
                (x instanceof String && y instanceof String) ||
                (x instanceof Number && y instanceof Number)) {
                return x.toString() === y.toString();
            }

            // At last checking prototypes as good as we can
            if (!(x instanceof Object && y instanceof Object)) {
                return false;
            }

            if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) {
                return false;
            }

            if (x.constructor !== y.constructor) {
                return false;
            }

            if (x.prototype !== y.prototype) {
                return false;
            }

            // Check for infinitive linking loops
            if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) {
                return false;
            }

            // Quick checking of one object being a subset of another.
            // todo: cache the structure of arguments[0] for performance
            for (p in y) {
                if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
                    return false;
                } else if (typeof y[p] !== typeof x[p]) {
                    return false;
                }
            }

            for (p in x) {
                if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
                    return false;
                } else if (typeof y[p] !== typeof x[p]) {
                    return false;
                }

                switch (typeof(x[p])) {
                    case 'object':
                    case 'function':

                        leftChain.push(x);
                        rightChain.push(y);

                        if (!compare2Objects(x[p], y[p])) {
                            return false;
                        }

                        leftChain.pop();
                        rightChain.pop();
                        break;

                    default:
                        if (x[p] !== y[p]) {
                            return false;
                        }
                        break;
                }
            }

            return true;
        }

        if (arguments.length < 1) {
            return true; //Die silently? Don't know how to handle such case, please help...
            // throw "Need two or more arguments to compare";
        }

        for (i = 1, l = arguments.length; i < l; i++) {

            leftChain = []; //Todo: this can be cached
            rightChain = [];

            if (!compare2Objects(arguments[0], arguments[i])) {
                return false;
            }
        }

        return true;
    }
    
    //判断一个js对象的所有属性是否为空值
    function isDeepEmpty(obj) {
        let props = Object.getOwnPropertyNames(obj);
        for (let i = 0; i < props.length; i++) {
            let prop = props[i];
            let value = obj[prop];
            // console.log(prop)
            if(!isEmpty(value)){
                return false;
            }
        }
        return true;
    }
    
    //判断变量值是否为空值
    function isEmpty(v) {
        switch (typeof v) {
            case 'undefined':
                return true;
            case 'string':
                if (v.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true;
                break;
            case 'boolean':
                if (!v) return true;
                break;
            case 'number':
                if (isNaN(v)) return true;
                break;
            case 'object':
                if (null === v || v.length === 0) return true;
                for (var i in v) {
                    return false;
                }
                return true;
        }
        return false;
    }
    
    //将js对象属性置null值
    function resetObj(obj) {
        let props = Object.getOwnPropertyNames(obj)
        for (let i = 0; i < props.length; i++) {
            let prop = props[i];
            obj[prop] = null;
        }
    }
    
    //提取选择的参数
    function getSelectionParams(selection,key) {
        let result = [];
        if(selection===null || selection.length===0){
            ElMessage.error(`selection中没有任何参数参数为${selection}`)
        }else{
            selection.forEach(s=>{
                result.push(s[key]);
            })
        }
        return result;
    }
    // console.log('Js判断空值')
    // console.log(isEmpty());              //true
    // console.log(isEmpty([]));            //true
    // console.log(isEmpty({}));            //true
    // console.log(isEmpty(0));             //true
    // console.log(isEmpty(Number("abc"))); //true
    // console.log(isEmpty(""));            //true
    // console.log(isEmpty("   "));         //true
    // console.log(isEmpty(false));         //true
    // console.log(isEmpty(null));          //true
    // console.log(isEmpty(undefined));     //true

    function recursionCascadeObj(obj,result,value,label){
        console.log('result：',result)
        if(obj.length!==0){
            obj.forEach(o=>{
                let item = {};
                item.value = o[value];
                item.label = o[label];
                if(o.children!=null && o.children.length!==0){//子集
                    item.children = [];
                    recursionCascadeObj(o.children,item.children,value,label);
                }
                result.push(item);
            })
        }
        return result;
    }

    //拼接数组请求参数
    function joinArrayReqParam(arr,paramName) {
        if(!arrUtils.checkArr(arr)){
            return;
        }
        let strUrl = '?';
        arr.forEach(id => {
            strUrl += paramName +  '=' + id + '&';
        })
        return strUrl;
    }

    //数据加载计时器
    //1.数据加载计时器
    function loadingTimer(load,msg) {
        load.value = true;
        let timer = setTimeout(function () {
            load.value = false;
            ElMessage.error(msg);
        },sys.loadingTime)
        
        function close() {
            load.value = false;
            clearTimeout(timer);
        }
        
        return {
            close
        }
    }
    
    //5.将数据转换树型结构
    // 参数说明：id 主键编号名称，parentId 父编号名称，children 子集名称
    function convertTree({data,id,parentId,children}) {
        if(!data || data.length===0){
            return [];
        }
        let treeData = [];
        //1.将要转换的数据缓存值map集合中
        let map = new Map();
        data.forEach(e=>{map.set(e[id],e)})
        // console.log('map:',map)
        // //2.找到集合的顶层元素
        map.forEach((v,k)=>{
            let flag = false;
            data.forEach(e=>{
                // console.log('id',e[id])
                // console.log('parentId',v[parentId])
                // console.log('....')
                if(v[parentId] === e[id]){
                    flag = true;//存在父级元素
                }
            })
            if(!flag){
                treeData.push(v);
                map.delete(k);
            }
        })
        // console.log('topData:',treeData)
        // //3.查找下级元素
        convertTreeChildren({
            upData: treeData,
            map:map,
            id:id,
            parentId: parentId,
            children: children
        })
        return treeData;
    }

    function convertTreeChildren({upData,map,id,parentId,children}) {
        // console.log('上层数据',upData)
        // console.log('剩余元素:',map)
        if (map.size !== 0){
            //上层元素的子元素
            map.forEach((v,k)=>{
                upData.forEach(e=>{
                    // console.log(e[id])
                    // let id1 = e[id];
                    // let parentId1 = v[parentId];
                    // console.log(`比较，上级元素编号：${id1}，剩余元素父编号：${parentId1}`)
                    if(v[parentId] === e[id]){
                        e[children] = e[children] ? e[children] : [];
                        e[children].push(v);
                        map.delete(k);
                        // e[children]
                    }
                })
            })
            //上层元素往下降一层
            upData.forEach(e=>{
                if(e[children]!==null && e[children]!==undefined && e[children].size!==0){
                    convertTreeChildren({
                        upData: e[children],
                        map: map,
                        id: id,
                        parentId: parentId,
                        children: children
                    })
                }
            })
        }
    }

    //4.克隆对象（深拷贝）
    function clone(obj) {
        if(obj === null) return null;
        if(typeof obj !== 'object') return obj;
        if(obj.constructor === RegExp) return new RegExp(obj);
        if(obj.constructor===Date) return new Date(obj);
        let newObj = {};
        Object.keys(obj).forEach(key=>{
            newObj[key] = clone(obj[key])
        })
        return newObj;
    }
    
    //2.清空搜索框（重置搜索框参数）
    function resetSearchParams({data,initData,hint,callback}) {
        if(deepCompare(data,initData)){
            //当前数据与原始数据相等
            if(hint){
                ElMessage.info('搜索框已被清空。')
            }
        }else{
            //当前数据与原始数据不相等
            Object.assign(data,initData);
            if(callback){
                //有回调函数调用回调函数
                callback();
            }
        }
    }
    
    //3.执行搜索任务
    function searchActive({data,initData,executeFn}) {
        if(deepCompare(data,initData)){
            ElMessage.info('请先输入搜索内容');
        }else{
            executeFn();
        }
    }
    
    //4.excel数据导出
    function exportExcel({data,fileName}){
        if(data){//返回对象不为空执行下载
            const blob = new Blob([data]);
            let url = window.URL.createObjectURL(blob);
            let link = document.createElement("a");
            link.style.display = "none";
            link.href = url;
            link.setAttribute('download',`${fileName}.xls`);
            document.body.appendChild(link);
            link.click();
        }
    }
    
    //5.查看当前时间是否在指定时间范围内
    function timeRange({startTime,endTime,beforeFn,afterFn,betweenFn}){
        let start = new Date(startTime);
        let end = new Date(endTime);
        let current = new Date();
        // console.log('currentDate:',current)
        // console.log(`开始时间${start}-结束时间${end}`)
        if(current < start){
            // console.log('当前时间还未到开始时间');
            if(beforeFn){
                beforeFn();
            }
            return 0;
        }else if(current >= end){
            // console.log('当前时间已到结束时间');
            if(afterFn){
                afterFn();
            }
            return -1;
        }else{
            // console.log('当前时间在时间范围内');
            if(betweenFn){
                betweenFn();
            }
            return 1;
        }
    }
    
    //6、计算两个时间相差的天数
    function calculateDaysBetween(startDate,endDate){
        const sDate = Date.parse(startDate)
        const eDate = Date.parse(endDate)
        if (sDate > eDate) {
            return 0
        }
        if (sDate === eDate) {
            return 1
        }
        return (eDate - sDate) / (1 * 24 * 60 * 60 * 1000)
    }
    
    //6、获取毫秒数的时长
    function getDuration(ms){
        return getDurationStr({
            ms: ms,
            d: true,
            h: true,
            m: true,
            s: true
        })
    }
    
    function getDurationStr({ms,d,h,m,s}){
        if(!ms) {
            return null;
        }
        // Math.floor() 去掉小数部分
        let se = ms/1000;
        let second = Math.floor(se%60);//取余秒数
        let minute = Math.floor(se/60%60);//多少分钟
        let hour = Math.floor(se/60/60%24);//多少小时
        let day = Math.floor(se/60/60/24);//多少天
        let returnStr = '';
        if(d && day!==0){
            returnStr+=`${day}天`;
        }
        if(h && hour!==0){
            returnStr+=`${hour}小时`;
        }
        if(m && minute!==0){
            returnStr+=`${minute}分钟`;
        }
        if(s){
            returnStr+=`${second}秒`;
        }
        return returnStr;
    }
    
    return{
        timeRange,
        searchActive,
        recursionCascadeObj,
        deepCompare,
        isEmpty,
        clone,
        isDeepEmpty,
        resetObj,
        joinArrayReqParam,
        loadingTimer,
        getSelectionParams,
        resetSearchParams,
        convertTree,
        arrUtils,
        exportExcel,
        getDuration,
        getDurationStr,
        calculateDaysBetween
    }
}();